package main

import (
	"flag"
	"gows/impl"
	"log"
	"net/http"
	"sync"
	"time"

	"github.com/bugfan/to"
	"github.com/gorilla/websocket"
)

var (
	Port       string
	Debug      bool
	MyUpgrader = websocket.Upgrader{
		// Allow cross domain
		CheckOrigin: func(r *http.Request) bool {
			return true
		},
	}
	MyConn Conn // all connection
)

func init() {
	// get cmd args
	flag.StringVar(&Port, "p", "9000", "listen port") // if -p=8080 then listen port is 8080 not 9000
	flag.Parse()
	// init data
	MyConn.Data = make(map[string]*impl.Connection)
}

type Conn struct {
	Data map[string]*impl.Connection
	sync.RWMutex
}

func wsHandler(w http.ResponseWriter, r *http.Request) {
	var (
		wsConn *websocket.Conn
		err    error
		data   []byte
		conn   *impl.Connection
	)
	if wsConn, err = MyUpgrader.Upgrade(w, r, nil); err != nil {
		log.Println("Upgrade fail:", err)
		return
	}
	if conn, err = impl.InitConnection(wsConn); err != nil {
		log.Println("init impl conn fail:", err)
		return
	}

	uuid := to.String(time.Now().Unix())

	MyConn.Lock()
	MyConn.Data[uuid] = conn // save conn
	MyConn.Unlock()
	defer func() { // release conn
		wsConn.Close()
		MyConn.Lock()
		delete(MyConn.Data, uuid) //delete conn
		MyConn.Unlock()
	}()

	go func() {
		var err error
		for {
			time.Sleep(10e9)
			if err = conn.WriteMessage([]byte(`heartbeat`)); err != nil {
				return
			}
		}
	}()
	for {
		if data, err = conn.ReadMessage(); err != nil {
			log.Println("Receive fail:", err)
			conn.Close()
			break
		}
		log.Println("Receive:", string(data))
		go broadcast(data)
	}
}

// send testing message to all online user
func broadcast(msg []byte) {
	MyConn.RLock()
	for _, v := range MyConn.Data {
		if err := v.WriteMessage(msg); err != nil {
			log.Println("Send fail:", err)
		}
	}
	MyConn.RUnlock()
}
func main() {
	http.HandleFunc("/api/v1/ws", wsHandler)
	http.ListenAndServe(":"+Port, nil)
}
